import base64
import hashlib
import pickle
from io import BytesIO

from fastapi import APIRouter
from matplotlib import pyplot as plt
from minio.error import S3Error
from seaman.core import JsonUtil
from typing import Dict


from common.method import *
from common.model import InterpolationData
from common.params import ReqSoftParams, SoftParams
from model.soft.soft_common import AxialForceResult, UniForceResult
from service.DataPreService import read_interpolation_data

router = APIRouter()



# 获取角度关系图数据
@router.post('/v3/angle/data')
async def angle_draw_data(params: ReqSoftParams):
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 获取插值数据
    interpolation_data_list: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    # 返回数据
    return interpolation_data_list

# 绘制角度关系图
@router.post('/v3/angle/draw')
async def angle_draw(params: ReqSoftParams):
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 获取插值数据
    interpolation_data_list: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    # 执行画图操作
    # 构建深度列表
    depth_list = [item.depth for item in interpolation_data_list]
    jxj_list = [item.inclination for item in interpolation_data_list]
    dog_list = [item.dog_leg_severity for item in interpolation_data_list]
    plt.rcParams['font.sans-serif'] = ["SimHei"]
    plt.rcParams['axes.unicode_minus'] = False  # 解决坐标轴负号显示问题
    fig, ax = plt.subplots()
    ax.plot(jxj_list, depth_list, color='r', label='井斜角')
    ax.plot(dog_list, depth_list, color='g', label='狗腿度')
    ax.xaxis.set_label_coords(0.5, 1.1)
    ax.xaxis.tick_top()
    ax.invert_yaxis()
    # plt.scatter(force_list, depth_list, marker='.', edgecolors='k')
    # 添加标题和标签
    plt.title("", loc='left', pad=5)
    plt.xlabel("角度(°)")
    plt.ylabel("深度(m)")
    plt.legend()
    # plt.show()
    buffer = BytesIO()
    plt.savefig(buffer, format='png')
    buffer.seek(0)
    # 上传文件
    putObject("well", wellId + '/角度关系图.png', buffer)
    return {
        'bucketName':'well',
        'objectName': wellId + '/角度关系图.png'
    }


# 接触力图
from model.soft.pull_axial_force import run as pull_run
from model.soft.push_axial_force import run as push_run
# 参数转化

# 获取接触力图数据 -> 可以较快计算获得就不存储
@router.post('/v3/touch/data')
async def touch_draw_data(params: ReqSoftParams):
    # 计算 MD5 哈希值
    md5_hash = params.calc_md5()
    print(md5_hash)
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 数据项
    data_object_name = wellId + '/' + md5_hash + '-touch.xlsx'
    try:
        client.stat_object('well', data_object_name)
        print('存在对应接触力数据')
        file_data = client.get_object("well", data_object_name)
        df = pd.read_excel(BytesIO(file_data.read()))
        data_list = []
        for index, row in df.iterrows():
            data_list.append(row)
        return data_list
    except S3Error:
        print('不存在对应接触力数据')
    # 获取插值数据
    interpolation_data_list: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    # 构建软件参数
    soft_params: SoftParams = SoftParams(params)
    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    # _list_ = get_test_data()
    result1: List[AxialForceResult] = pull_run(soft_params, interpolation_data_list, is_Not_add_resistance)
    # for item in result1:
    #     print(JsonUtil.obj2str(item))
    result2: List[AxialForceResult] = push_run(soft_params, interpolation_data_list, is_Not_add_resistance)
    # for item in result2:
    #     print(JsonUtil.obj2str(item))
    result_arr = []
    data_len: int = len(result1)
    for idx in range(0, data_len):
        obj = {}
        obj['depth'] = result1[idx].depth
        obj['N_pull'] = result1[idx].N
        obj['N_push'] = result2[idx].N
        result_arr.append(obj)
    df = pd.DataFrame(result_arr)
    # 生成并上传Excel数据
    excel_data = df
    # 将数据写入Excel文件
    excel_file = io.BytesIO()
    excel_data.to_excel(excel_file, index=False)
    excel_file.seek(0)
    putObject('well', data_object_name, excel_file)
    return result_arr

@router.post('/v3/touch/draw')
async def touch_draw(params: ReqSoftParams):
    # 计算 MD5 哈希值
    md5_hash = params.calc_md5()
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 构建对象名称
    image_object_name = wellId + '/' + md5_hash + '-接触力图.png'
    try:
        client.stat_object('well', image_object_name)
        print('已存在对应接触力图')
        return {
            'bucketName': 'well',
            'objectName': image_object_name
        }
    except S3Error:
        print('不存在对应接触力图')
    # 获取插值数据
    interpolation_data_list: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    # 构建软件参数
    soft_params: SoftParams = SoftParams(params)
    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    # _list_ = get_test_data()
    result1: List[AxialForceResult] = pull_run(soft_params, interpolation_data_list, is_Not_add_resistance)
    for item in result1:
        print(JsonUtil.obj2str(item))
    result2: List[AxialForceResult] = push_run(soft_params, interpolation_data_list, is_Not_add_resistance)
    for item in result2:
        print(JsonUtil.obj2str(item))
    depth_list = [item.depth for item in result1]
    # 接触力1
    force_list1 = [item.N for item in result1]
    # 接触力2
    force_list2 = [item.N for item in result2]
    plt.rcParams['font.sans-serif'] = ["SimHei"]
    plt.rcParams['axes.unicode_minus'] = False  # 解决坐标轴负号显示问题
    fig, ax = plt.subplots()
    ax.plot(force_list1, depth_list, color='r', label='上提')
    ax.plot(force_list2, depth_list, color='g', label='下放')
    ax.xaxis.set_label_coords(0.5, 1.1)
    ax.xaxis.tick_top()
    ax.invert_yaxis()
    # plt.scatter(force_list, depth_list, marker='.', edgecolors='k')
    # 添加标题和标签
    plt.title("接触力分析图", loc='left', pad=5)
    plt.xlabel("接触力(N)")
    plt.ylabel("深度(m)")
    plt.legend()
    # plt.show()
    buffer = BytesIO()
    plt.savefig(buffer, format='png')
    buffer.seek(0)
    # 上传文件
    putObject("well", image_object_name, buffer)
    return {
        'bucketName': 'well',
        'objectName': image_object_name
    }



@router.post('/v3/axial/data')
async def axial_draw_data(params: ReqSoftParams):
    # 计算 MD5 哈希值
    md5_hash = params.calc_md5()
    print(md5_hash)
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 数据项
    data_object_name = wellId + '/' + md5_hash + '-axial.xlsx'
    try:
        client.stat_object('well', data_object_name)
        print('存在对应轴力数据')
        file_data = client.get_object("well", data_object_name)
        df = pd.read_excel(BytesIO(file_data.read()))
        data_list = []
        for index, row in df.iterrows():
            data_list.append(row)
        return data_list
    except S3Error:
        print('不存在对应轴力数据')
    # 获取插值数据
    interpolation_data_list: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    # 构建软件参数
    soft_params: SoftParams = SoftParams(params)
    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    # _list_ = get_test_data()
    result1: List[AxialForceResult] = pull_run(soft_params, interpolation_data_list, is_Not_add_resistance)
    # for item in result1:
    #     print(JsonUtil.obj2str(item))
    result2: List[AxialForceResult] = push_run(soft_params, interpolation_data_list, is_Not_add_resistance)
    # for item in result2:
    #     print(JsonUtil.obj2str(item))
    result_arr = []
    data_len: int = len(result1)
    for idx in range(0, data_len):
        obj = {}
        obj['depth'] = result1[idx].depth
        obj['F_pull'] = result1[idx].F
        obj['F_push'] = result2[idx].F
        result_arr.append(obj)
    df = pd.DataFrame(result_arr)
    # 生成并上传Excel数据
    excel_data = df
    # 将数据写入Excel文件
    excel_file = io.BytesIO()
    excel_data.to_excel(excel_file, index=False)
    excel_file.seek(0)
    putObject('well', data_object_name, excel_file)
    return result_arr
# 轴力分析图 + 接触力图 可以放在一起绘制
@router.post('/v3/axial/draw')
async def axial_draw(params: ReqSoftParams):
    # 计算 MD5 哈希值
    md5_hash = params.calc_md5()
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 构建对象名称 @TODO
    image_object_name = wellId + '/' + md5_hash + '-轴力分析图.png'
    try:
        client.stat_object('well',image_object_name)
        print('已存在对应轴力分析图')
        return {
            'bucketName': 'well',
            'objectName': image_object_name
        }
    except S3Error:
        print('不存在对应轴力分析图')
    # 参数预处理
    soft_params: SoftParams = SoftParams(params)
    # 获取插值数据
    _list_: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    # _list_ = get_test_data()
    result1 = pull_run(soft_params, _list_, is_Not_add_resistance)

    result2 = push_run(soft_params, _list_, is_Not_add_resistance)


    depth_list = [item.depth for item in result1]
    # 张力1
    force_list1 = [item.F / 1000 for item in result1]
    # 张力2
    force_list2 = [item.F / 1000 for item in result2]
    plt.rcParams['font.sans-serif'] = ["SimHei"]
    plt.rcParams['axes.unicode_minus'] = False  # 解决坐标轴负号显示问题
    fig, ax = plt.subplots()
    ax.plot(force_list1, depth_list, color='r', label='上提轴力')
    ax.plot(force_list2, depth_list, color='g', label='下放轴力')
    ax.xaxis.set_label_coords(0.5, 1.1)
    ax.xaxis.tick_top()
    ax.invert_yaxis()
    # plt.scatter(force_list, depth_list, marker='.', edgecolors='k')
    # 添加标题和标签
    plt.title("轴力分析图", loc='left', pad=5)
    plt.xlabel("轴力(kN)")
    plt.ylabel("深度(m)")
    plt.legend()
    # plt.show()
    buffer = BytesIO()
    plt.savefig(buffer, format='png')
    buffer.seek(0)
    # 上传文件
    putObject("well", image_object_name, buffer)
    return {
        'bucketName': 'well',
        'objectName': image_object_name
    }



# 上提下放张力
from strain.cable_strain import run as strain_run


@router.post('/v3/tension/data')
async def tension_draw_data(params: ReqSoftParams):
    # 计算 MD5 哈希值
    md5_hash = params.calc_md5()
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 构建对象名称
    data_object_name = wellId + '/' + md5_hash + '-strain.xlsx'
    print(data_object_name)
    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    try:
        client.stat_object('well', data_object_name)
        print('已存在对应张力分析数据')
        file_data = client.get_object("well", data_object_name)
        df = pd.read_excel(BytesIO(file_data.read()))
        data_list = []
        for index, row in df.iterrows():
            data_list.append(row)
        return data_list
    except S3Error:
        print('不存在张力分析数据')
        # 参数预处理
    soft_params: SoftParams = SoftParams(params)
    # 获取插值数据
    _list_: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    max_depth: float = _list_[-1].depth
    inc_dict: Dict = {}
    for item in _list_:
        inc_dict[item.depth] = item.inclination
    # soft_params.build_f_hel(inc_dict, max_depth)
    # _list_ = get_test_data()
    # 计算的间距
    calculate_space = params.calculate_space
    last_depth = _list_[-1].depth
    # 设置间隔深度列表
    desired_depths = [last_depth]
    # 从最后一个深度开始，减去间距，直到小于间距为止 这样就只计算部分深度
    while desired_depths[-1] > calculate_space:
        new_value = desired_depths[-1] - calculate_space
        desired_depths.append(new_value)
        # 对列表进行排序并去除重复值
    desired_depths = sorted(set(desired_depths), reverse=True)
    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    # 井口摩擦力设置
    wellhead_friction: float = params.wellhead_friction
    result = strain_run(soft_params, _list_, is_Not_add_resistance, desired_depths, wellhead_friction)
    save('well', data_object_name, result)
    return result




@router.post('/v3/tension/draw')
async def tension_draw(params: ReqSoftParams):
    # 计算 MD5 哈希值
    md5_hash = params.calc_md5()
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 构建对象名称
    image_object_name = wellId + '/' + md5_hash + '-张力分析图.png'
    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    try:
        client.stat_object('well', image_object_name)
        print('已存在对应张力分析图')
        return {
            'bucketName': 'well',
            'objectName': image_object_name
        }
    except S3Error:
        print('不存在对应张力分析图')
        # 参数预处理
    soft_params: SoftParams = SoftParams(params)
    # 获取插值数据
    _list_: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    max_depth: float = _list_[-1].depth
    inc_dict: Dict = {}
    for item in _list_:
        inc_dict[item.depth] = item.inclination
    # soft_params.build_f_hel(inc_dict, max_depth)
    # 计算的间距
    calculate_space = params.calculate_space
    last_depth = _list_[-1].depth
    # 设置间隔深度列表
    desired_depths = [last_depth]
    # 从最后一个深度开始，减去间距，直到小于间距为止 这样就只计算部分深度
    while desired_depths[-1] > calculate_space:
        new_value = desired_depths[-1] - calculate_space
        desired_depths.append(new_value)
        # 对列表进行排序并去除重复值
    desired_depths = sorted(set(desired_depths), reverse=True)

    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    # 井口摩擦力设置
    wellhead_friction: float = params.wellhead_friction
    result = strain_run(soft_params, _list_, is_Not_add_resistance, desired_depths, wellhead_friction)
    # for item in result:
    #     print(JsonUtil.obj2str(item))
    # return 0.0
    depth_list = [item.depth for item in result]
    f_pull_list = [item.F_pull / 1000 for item in result]
    f_push_list = [item.F_push / 1000 for item in result]
    f_w_l_list = [item.F_weak_low / 1000 for item in result]
    f_w_h_list = [item.F_weak_high / 1000 for item in result]
    f_w_rate_list = [item.F_weak_rate_low / 1000 for item in result]
    # 50% 安全操作力
    safe_list = [soft_params.F_break * 0.5 for item in result]

    plt.rcParams['font.sans-serif'] = ["SimHei"]
    plt.rcParams['axes.unicode_minus'] = False  # 解决坐标轴负号显示问题
    fig, ax = plt.subplots()
    ax.plot(f_pull_list, depth_list, color='r', label='上提张力')
    ax.plot(f_push_list, depth_list, color='k', label='下放张力')
    ax.plot(f_w_rate_list, depth_list, color='b', label='{}%弱点张力'.format(round(params.F_weak_rate_low * 100/params.F_weak_low)))
    ax.plot(f_w_h_list, depth_list, color='pink', label='弱点张力(High)')
    ax.plot(f_w_l_list, depth_list, color='g', label='弱点张力(Low)')
    ax.plot(safe_list, depth_list, color='orange', label='50%安全操作张力')
    ax.xaxis.set_label_coords(0.5, 1.1)
    ax.xaxis.tick_top()
    ax.invert_yaxis()
    # plt.scatter(force_list, depth_list, marker='.', edgecolors='k')
    # 添加标题和标签
    plt.title("张力图", loc='left', pad=5)
    plt.xlabel("张力(KN)")
    plt.ylabel("深度(m)")
    plt.legend()
    # plt.show()
    buffer = BytesIO()
    plt.savefig(buffer, format='png')
    buffer.seek(0)

    # 上传文件
    putObject("well", image_object_name, buffer)
    return {
        'bucketName': 'well',
        'objectName': image_object_name
    }

from model.soft.cable_tension import run as cable_run

# 缆头数据
@router.post('/v3/cable/data')
async def cable_tension_draw_data(params: ReqSoftParams):
    # 计算 MD5 哈希值
    md5_hash = params.calc_md5()
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 构建对象名称
    data_object_name = wellId + '/' + md5_hash + '-cable_tension.xlsx'
    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    try:
        client.stat_object('well', data_object_name)
        print('已存在对应缆头张力分析数据')
        file_data = client.get_object("well", data_object_name)
        df = pd.read_excel(BytesIO(file_data.read()))
        data_list = []
        for index, row in df.iterrows():
            data_list.append(row)
        return data_list
    except S3Error:
        print('不存在缆头张力分析数据')
    # 参数预处理
    soft_params: SoftParams = SoftParams(params)

    # 获取插值数据
    _list_: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    # 计算的间距
    calculate_space = params.calculate_space
    last_depth = _list_[-1].depth
    # 设置间隔深度列表
    desired_depths = [last_depth]
    # 从最后一个深度开始，减去间距，直到小于间距为止 这样就只计算部分深度
    while desired_depths[-1] > calculate_space:
        new_value = desired_depths[-1] - calculate_space
        desired_depths.append(new_value)
        # 对列表进行排序并去除重复值
    desired_depths = sorted(set(desired_depths), reverse=True)

    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    result = cable_run(soft_params, _list_, is_Not_add_resistance, desired_depths)
    save('well',data_object_name, result)
    return result


@router.post('/v3/cable/draw')
async def cable_tension_draw(params: ReqSoftParams):
    # 计算 MD5 哈希值
    md5_hash = params.calc_md5()
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 构建对象名称
    image_object_name = wellId + '/' + md5_hash + '-缆头张力图.png'
    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    try:
        client.stat_object('well', image_object_name)
        print('已存在对应缆头张力图')
        return {
            'bucketName': 'well',
            'objectName': image_object_name
        }
    except S3Error:
        print('不存在对应缆头张力图')
    # 参数预处理
    soft_params: SoftParams = SoftParams(params)
    # 获取插值数据
    _list_: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    # _list_ = get_test_data()
    # 计算的间距
    calculate_space = params.calculate_space
    last_depth = _list_[-1].depth
    # 设置间隔深度列表
    desired_depths = [last_depth]
    # 从最后一个深度开始，减去间距，直到小于间距为止 这样就只计算部分深度
    while desired_depths[-1] > calculate_space:
        new_value = desired_depths[-1] - calculate_space
        desired_depths.append(new_value)
        # 对列表进行排序并去除重复值
    desired_depths = sorted(set(desired_depths), reverse=True)

    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    result = cable_run(soft_params, _list_, is_Not_add_resistance, desired_depths)
    # for item in result:
    #     print(JsonUtil.obj2str(item))
    depth_list = [item.depth for item in result]
    F_pull_list = [item.F_pull / 1000 for item in result]
    F_push_list = [item.F_push / 1000 for item in result]
    plt.rcParams['font.sans-serif'] = ["SimHei"]
    plt.rcParams['axes.unicode_minus'] = False  # 解决坐标轴负号显示问题
    fig, ax = plt.subplots()
    ax.plot(F_pull_list, depth_list, color='r', label='上提缆头张力')
    ax.plot(F_push_list, depth_list, color='k', label='下放缆头张力')
    ax.xaxis.set_label_coords(0.5, 1.1)
    ax.xaxis.tick_top()
    ax.invert_yaxis()
    # plt.scatter(force_list, depth_list, marker='.', edgecolors='k')
    # 添加标题和标签
    plt.title("缆头张力图", loc='left', pad=5)
    plt.xlabel("张力(KN)")
    plt.ylabel("深度(m)")
    plt.legend()
    # plt.show()
    buffer = BytesIO()
    plt.savefig(buffer, format='png')
    buffer.seek(0)

    # 上传文件
    putObject("well", image_object_name, buffer)
    return {
        'bucketName': 'well',
        'objectName': image_object_name
    }



from model.soft.pull_tension import run as pull_tension_run

@router.post('/v3/alone/data')
async def pull_tension_data(params: ReqSoftParams):
    # 计算 MD5 哈希值
    md5_hash = params.calc_md5()
    print(md5_hash)
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 数据项
    data_object_name = wellId + '/' + md5_hash + '-pull_tension.xlsx'
    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    try:
        client.stat_object('well', data_object_name)
        print('存在对应上提张力数据')
        file_data = client.get_object("well", data_object_name)
        df = pd.read_excel(BytesIO(file_data.read()))
        data_list = []
        for index, row in df.iterrows():
            data_list.append(row)
        return data_list
    except S3Error:
        print('不存在对应上提张力数据')
    # 构建软件参数
    soft_params: SoftParams = SoftParams(params)
    # 获取插值数据
    _list_: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    # _list_ = get_test_data()
    result = pull_tension_run(soft_params, _list_, is_Not_add_resistance)
    save('well', data_object_name, result)
    return result